/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.oimwrapper.scheduledtasks;

import java.util.*;
import java.io.*;

import Thor.API.*;
import Thor.API.Operations.*;
import org.oimwrapper.connectors.OIMTaskBase;
import org.oimwrapper.connectors.exceptions.OIMMissingAttributeException;
import org.oimwrapper.csvreader.CsvReader;
import org.oimwrapper.csvreader.CsvWriter;
import org.oimwrapper.oimutils.StringUtils;



public class OIMTools extends OIMTaskBase {

    private boolean stop = false;
    private String userId;
    private String userKey;
    private String resourceName;
    private boolean active = true;
    private String command;

    private tcProvisioningOperationsIntf provOp;
    private TaskDefinitionOperationsIntf taskDefOp;

    public OIMTools() {
        super("OIM.OIMTOOLS");
    }

    public void execute() {
        logger.info("OIM Tools Starting");
        
        command = getDefaultAttribute("command", "");
        
        if (StringUtils.isEmpty(command))
            throw new RuntimeException("Invalid Command");
        
        if (command.equalsIgnoreCase("loadlookup")) {
            loadLookupFromFile();
            return;
        }
        if (command.equalsIgnoreCase("exportlookup")) {
            exportLookupToFile();
            return;
        }
        
        if (command.equalsIgnoreCase("runtask")) {
            runTask();
            return;
        }
        
        userId = getAttribute("User Id");
        userKey = getAttribute("User Key");
        resourceName = getAttribute("Resource Name");
        active = getBooleanAttribute("active", true);
        
        logger.debug("Parms " + this.getTaskAttributeMap());



        if (command.equalsIgnoreCase("showresources")) {
            showResources();
        }
        if (command.equalsIgnoreCase("showuser")) {
            showUser();
        }
        if (command.equalsIgnoreCase("showresourcedata")) {
            showResourceData();
        }
        
        
        if (command.equalsIgnoreCase("runtaskforuser")) {
            runTaskForUser();
        }

        logger.info("OIM Tools Leaving");

    }

    private void runTaskForUser()
    {
        String fileName = null;
        String resName = null;
        String taskName = null;
        String resStatus = null;

        CsvReader reader = null;

        try {
            resName = getCriticalAttribute("resourceName");
            taskName = getCriticalAttribute("taskName");
            resStatus = getCriticalAttribute("resourceStatus");
            fileName = getCriticalAttribute("File Name");

        } catch (OIMMissingAttributeException ex) {
            logger.error("Missing Attribute for runTask operation");
            return;
        }

        long objKey = 0L;
        try {
            objKey = getResourceObject(resName);
        } catch (Exception e) {
            logger.error("Error getting obj Key ", e);
            return;
        }
        
        try
        {
            reader = new CsvReader(fileName);
            reader.readHeaders();
            String[] fileHeaders = reader.getHeaders();

            while (reader.readRecord())
            {
                if (stop)
                    break;

                userId = reader.get("USERID");
                if (StringUtils.isEmpty(userId))
                {
                    continue;
                }
                userId = userId.toUpperCase();
                logger.info("Running Task " + taskName + " for " + userId);
                String qry =
                "select orc_key " +
                "from oiu,usr " +
                "where oiu.usr_key = usr.usr_key and " +
                "UPPER(usr.usr_login)='" + userId + "' and " +
                "oiu.ost_key=(Select ost_key from ost where " +
                "obj_key=" +
                "'" + objKey + "'" +
                "and OST_status=" +
                "'" + resStatus + "')";

                logger.debug(qry);
                Map[] keys = null;
                try {
                    keys = getOimData(qry);
                } catch (Exception e) {
                    logger.error("Error running query ", e);
                    return;
                }
                long[] result = new long[keys.length];
                for (int i = 0; !stop && i < result.length; i++) {
                    logger.info("Key " + keys[i].get("Process Instance.Key"));
                    String strKey = (String)keys[i].get("Process Instance.Key");
                    processSingleInstance(Long.parseLong(strKey),taskName);
                }

            }

        }
        catch(FileNotFoundException fnfe)
        {
            logger.error("File Not Found");
            return;
        }
        catch(IOException ioe)
        {
            logger.error("File IO Error " + ioe.getMessage());
            return;
        }
        finally
        {
            if (reader != null)
                reader.close();
        }

    }

    private void runTask() {
        
        String resName = null;
        String taskName = null;
        String resStatus = null;
        try {
            resName = getCriticalAttribute("resourceName");
            taskName = getCriticalAttribute("taskName");
            resStatus = getCriticalAttribute("resourceStatus");

        } catch (OIMMissingAttributeException ex) {
            logger.error("Missing Attribute for runTask operation");
            return;
        }
        long objKey = 0L;
        try {
            objKey = getResourceObject(resName);
        } catch (Exception e) {
            logger.error("Error getting obj Key ", e);
            return;
        }

        String qry =
                "select orc_key " +
                "from oiu,usr " +
                "where oiu.usr_key = usr.usr_key and " +
                "oiu.ost_key=(Select ost_key from ost where " +
                "obj_key=" +
                "'" + objKey + "'" +
                "and OST_status=" +
                "'" + resStatus + "')";

        Map[] keys = null;
        try {
            keys = getOimData(qry);
        } catch (Exception e) {
            logger.error("Error running query ", e);
            return;
        }
        long[] result = new long[keys.length];
        for (int i = 0; !stop && i < result.length; i++) {
            logger.info("Key " + keys[i].get("Process Instance.Key"));
            String strKey = (String)keys[i].get("Process Instance.Key");
            processSingleInstance(Long.parseLong(strKey),taskName);
        }
    }

    private void processSingleInstance(long ProcessInstanceKey,String TaskName) {
        try {
            provOp = (tcProvisioningOperationsIntf) getUtility(tcProvisioningOperationsIntf.class);
            taskDefOp = (TaskDefinitionOperationsIntf)getUtility(TaskDefinitionOperationsIntf.class);

            //String TaskName = getCriticalAttribute("TaskName");
            Map searchFor = new HashMap();
            searchFor.put("Process Definition.Tasks.Task Name", TaskName);
            tcResultSet tasks = taskDefOp.getTaskDetail(ProcessInstanceKey, searchFor);
            if (tasks.getRowCount() == 1) {
                provOp.addProcessTaskInstance(tasks.getLongValue("Process Definition.Tasks.Key"), ProcessInstanceKey);
            }
        } catch (Exception e) {
            logger.error("Error Running Task " + e.getMessage(),e);
        }
    }

    private void loadLookupFromFile() {
        String filename = getAttribute("File Name");
        String lookupname = getAttribute("LookUp Table");

        if (StringUtils.isEmpty(lookupname))
        {
            logger.error("Must Specify Lookup Name");
            return;
        }

        if (StringUtils.isEmpty(filename))
        {
            logger.error("Must Specify File Name");
            return;
        }


        CsvReader rdr = null;
        HashMap newLkUp = new HashMap();
        try {
            rdr = new CsvReader(filename);
            rdr.readHeaders();

            while (rdr.readRecord()) {
                String decode = rdr.get("KEY");
                String encode = rdr.get("VALUE");
                if (!StringUtils.isEmpty(encode) && !StringUtils.isEmpty(decode)) {
                    newLkUp.put(decode, encode);
                }
            }
        } catch (FileNotFoundException fnfe) {
            logger.error("File Not Found " + filename);
        } catch (IOException ioe) {
            logger.error("IO Error ", ioe);
        }

        if (newLkUp.isEmpty()) {
            logger.error("No Records");
            return;
        }

        try {
            this.removeLookup(lookupname);
        } catch (Exception e) {
            logger.error("Remove Lookup Failed");
            //return;
        }
        try {
            this.createLookup(lookupname);
        } catch (Exception e) {
            logger.error("Create Lookup Failed");
            return;
        }

        try {
            logger.debug("Loading " + newLkUp.size() + " Records");
            Iterator i = newLkUp.keySet().iterator();
            while (i.hasNext()) {
                String l = (String) i.next();
                String r = (String) newLkUp.get(l);
                addLookupValue(l, r, lookupname);
            }
        } catch (Exception e) {
            logger.error("Add Lookup Entry Failed");
        }



    }

    private void exportLookupToFile()
    {

        String filename = getAttribute("File Name");
        String lookupname = getAttribute("LookUp Table");

        if (StringUtils.isEmpty(lookupname))
        {
            logger.error("Must Specify Lookup Name");
            return;
        }

        if (StringUtils.isEmpty(filename))
        {
            logger.error("Must Specify File Name");
            return;
        }


        Map keys = null;

        try
        {
            keys = getLookupValues(lookupname);
        }
        catch(Exception e)
        {
            logger.error(e.getMessage(),e);
            return;
        }

        CsvWriter writer = null;
        try
        {
            writer = new CsvWriter(filename);
            writer.write("KEY");
            writer.write("VALUE");
            writer.endRecord();

            Set keyset = keys.keySet();
            Iterator i = keyset.iterator();
            while(i.hasNext())
            {
                String key = (String)i.next();
                String val = (String)keys.get(key);
                writer.write(key);
                writer.write(val);
                writer.endRecord();
            }
        }
        catch(FileNotFoundException fnfe)
        {
            logger.error("Filenotfound " + filename);
            return;
        }
        catch(IOException ioe)
        {
            logger.error("IO Error",ioe);
            return;
        }
        finally
        {
            if (writer != null)
                writer.close();
        }

    }
    
    private void showResources() {

        if (StringUtils.isEmpty(userId))
        {
            logger.error("Must Specify a User Id");
            return;
        }

        logger.debug("Status Option " + active);
        try {
            Map[] myMap = null;
            if (StringUtils.isEmpty(resourceName)) {
                myMap = getObjectsForUser(userId, active);
            } else {
                myMap = getObjectsForUser(resourceName, userId, active);
            }

            logger.info("Found " + myMap.length + " Resources");

            for (int i = 0; i < myMap.length; i++) {
                logger.info("Name " +
                        myMap[i].get("Process.Process Definition.Process Form Name"));
                logger.info("Status " +
                        myMap[i].get("Objects.Object Status.Status"));

                logger.info("Resource " + myMap[i]);
            }
        } catch (Exception e) {
            logger.error("Exception", e);
        }
        return;
    }

    private void showUser() {
        if (!validate()) {
            return;
        }

        try {
            Map myMap = this.getOimUserData(userId);
            logger.info("User Data for " + userId);
            logger.info("User Data " + myMap);
        } catch (Exception e) {
            logger.error("showUser exception", e);
        }
    }

    public void showResourceData() {
        
        if (StringUtils.isEmpty(resourceName)) {
            logger.error("Must specify resourceName");
            return;
        }

        if (StringUtils.isEmpty(userId)) {
            logger.error("Must specify userID");
            return;
        }

        showResources();
        logger.info("Getting Resource " + resourceName + " for " + userId);
        long pik = getPIK(resourceName, userId);
        if (pik == 0l) {
            logger.error("No Process Data Found for " + resourceName + " pic " + pik);
            return;
        }

        Map prMap = null;
        try {
            prMap = this.getProcessFormValues(pik);
        } catch (Exception e) {
            logger.error("getProcessFormValues failed ", e);
            return;
        }

        logger.info("Process Data ");
        logger.info(" " + prMap);

        String[] childTables = null;
        try {
            childTables = this.getChildTables(pik);
            if (childTables == null || childTables.length == 0) {
                return;
            }
        } catch (Exception e) {
            logger.error("getChildTables failed ", e);
            return;
        }

        for (int i = 0; i < childTables.length; i++) {
            if (!StringUtils.isEmpty(childTables[i])) {
                Map[] chMaps = null;
                try {
                    chMaps = getProcessFormChildValues(pik, childTables[i]);
                } catch (Exception e) {
                    logger.error("getProcessFormChildValues failed " +
                            childTables[i]);
                    logger.error("getProcessFormChildValues failed ", e);
                    return;
                }

                if (chMaps == null || chMaps.length == 0) {
                    return;
                }
                for (int x = 0; x < chMaps.length; x++) {
                    logger.info("Children ");
                    logger.info(" " + chMaps[i]);
                }
            }
        }

    }

    public long getPIK(String res, String usr) {
        long ret = 0l;
        logger.debug("getpik " + res + " " + usr);
        String usrKeyStr = null;
        long usrKey = 0l;

        try {
            usrKeyStr = this.getOimUserAttribute(userId, "Users.Key");
            usrKey = new Long(usrKeyStr).longValue();
        } catch (Exception e) {
            logger.error("getOimUserAttribute failed ", e);
            return 0l;
        }

        ArrayList activeList = new ArrayList();

        try {
            Map[] myMap = this.getObjectsForUser(resourceName, usrKey, false);
            logger.debug("Found " + myMap.length + " PIKS");

            for (int i = 0; i < myMap.length; i++) {
                String stat = (String) myMap[i].get("Objects.Object Status.Status");
                if (stat.equalsIgnoreCase("ENABLED") ||
                        stat.equalsIgnoreCase("PROVISIONED")) {
                    activeList.add(myMap[i]);
                }
            }
            if (activeList.size() == 0) {
                logger.debug("No Active Resources found");
                return 0l;
            }
            if (activeList.size() > 1) {
                logger.debug("Too Many Active Resources");
                return 0l;
            }
            Map activeMap = (Map) activeList.get(0);
            String strPik = (String) activeMap.get("Process Instance.Key");
            logger.debug("Resource Object Values " + myMap[0]);
            ret = new Long(strPik).longValue();

        } catch (Exception e) {
            logger.error("Exception", e);
        }
        return ret;

    }

    private boolean validate() {
        if (StringUtils.isEmpty(userId) && StringUtils.isEmpty(userKey)) {
            logger.error("Userid and User Key is empty");
            return false;
        }
        return true;


    }

    public boolean stop() {
        stop = true;
        return stop;
    }
}
